package com.zeus.common.utils;

import com.zeus.common.constants.ZeusConstant;
import com.zeus.common.log.ZeusLoggerConfig;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.io.InputStream;
import java.lang.management.ManagementFactory;
import java.lang.management.RuntimeMXBean;
import java.net.Inet4Address;
import java.net.InetAddress;
import java.net.InterfaceAddress;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.net.UnknownHostException;
import java.util.Enumeration;
import java.util.List;
import java.util.Properties;

/**
 * 服务信息获取工具
 *
 * @author f1ybear_wang
 * @date 2020/9/13  23:31
 **/
public class ServerInfoUtils {
    private final static Logger logger = LoggerFactory.getLogger(ServerInfoUtils.class);

    /**
     * 中横线
     */
    private static final String HYPHEN = "-";

    /**
     * 防止私有化
     *
     * @author f1ybear_wang
     * @date 2020/9/13 23:32
     */
    private ServerInfoUtils() {
        // default
    }

    /**
     * 获取服务器ip地址
     *
     * @return ip地址
     * @author f1ybear_wang
     * @date 2020/9/13 23:32
     */
    public static String getHostIp() {
        try {
            final Enumeration<NetworkInterface> interfaces = NetworkInterface.getNetworkInterfaces();
            while (interfaces.hasMoreElements()) {
                final NetworkInterface cur = interfaces.nextElement();
                if (cur.isLoopback() || cur.isVirtual()) {
                    continue;
                }
                for (final InterfaceAddress addr : cur.getInterfaceAddresses()) {
                    final InetAddress inetAddress = addr.getAddress();

                    if (inetAddress instanceof Inet4Address && !inetAddress.isLoopbackAddress()) {
                        return inetAddress.getHostAddress();
                    }
                }
            }
        } catch (SocketException e) {
            if (logger.isWarnEnabled() && ZeusLoggerConfig.needEnableLogger()) {
                logger.warn("### Zeus报警服务, 获取服务器IP, 地址错误 >> errMsg = {}", e.getMessage());
            }
        }
        return ZeusConstant.UNKNOWN;
    }

    /**
     * 获取服务器hostName
     *
     * @return 服务器hostName
     * @author wangfeixiong126@gmail.com  2021/5/13 19:03
     */
    public static String getHostName() {
        try {
            String hostname = null;
            try {
                hostname = InetAddress.getLocalHost().getHostName();
            } catch (UnknownHostException uhe) {
                String host = uhe.getMessage();
                if (host != null) {
                    int colon = host.indexOf(':');
                    if (colon > 0) {
                        return host.substring(0, colon);
                    }
                }
            }
            if (hostname != null && !hostname.isEmpty() && hostname.contains(HYPHEN)) {
                return hostname;
            }
            InputStream is = null;
            try {
                Process p = Runtime.getRuntime().exec("hostname");
                byte[] hostBytes = new byte[1024];
                is = p.getInputStream();
                int readed = is.read(hostBytes);
                p.waitFor();
                hostname = new String(hostBytes, 0, readed);
                if (!hostname.isEmpty()) {
                    return hostname;
                }
            } catch (Throwable e) {
                if (logger.isWarnEnabled() && ZeusLoggerConfig.needEnableLogger()) {
                    logger.warn("### Zeus报警服务, 获取服务器hostName出错了 >> errMsg = {}", e.getMessage());
                }
            } finally {
                if (is != null) {
                    try {
                        is.close();
                    } catch (IOException e) {
                        if (logger.isWarnEnabled() && ZeusLoggerConfig.needEnableLogger()) {
                            logger.warn("### Zeus报警服务, 获取服务器hostName出错了 >> errMsg = {}", e.getMessage());
                        }
                    }
                }
            }
            return ZeusConstant.UNKNOWN;
        } catch (Exception e) {
            if (logger.isWarnEnabled() && ZeusLoggerConfig.needEnableLogger()) {
                logger.warn("### Zeus报警服务, 获取服务器hostName失败 >> errMsg = {}", e.getMessage());
            }
        }
        return ZeusConstant.UNKNOWN;
    }

    /**
     * 初始化应用appId
     *
     */
    public static String getAppId() {
        try {
            // 系统属性中获取
            String appId = System.getProperty("app.id");
            if (appId != null && !appId.isEmpty()) {
                return appId;
            }
            appId = System.getenv("APP_ID");
            if (appId != null && !appId.isEmpty()) {
                return appId;
            }

            // 启动参数中获取
            RuntimeMXBean bean = ManagementFactory.getRuntimeMXBean();
            // -Dapp.id=koo-daxue-promote-service
            List<String> list = bean.getInputArguments();
            for (String item : list) {
                if (item.startsWith("-Dapp.id")) {
                    appId = item.substring(9);
                    return appId;
                }
            }

            // 配置文件中获取appid
            appId = AppProperties.getAppId();
            if (appId != null) {
                return appId;
            }
        } catch (Exception e) {
            if (logger.isWarnEnabled() && ZeusLoggerConfig.needEnableLogger()) {
                logger.warn("### 宙斯初始化应用appId信息出现异常 >> errMsg = {}", e.getMessage());
            }
        }
        return ZeusConstant.UNKNOWN;
    }

    /**
     * 初始化应用运行环境变量信息
     *
     */
    public static String getEnv() {
        try {
            // 系统属性中获取
            String envCode = System.getProperty("env");
            if (envCode != null && !envCode.isEmpty()) {
                return envCode.toLowerCase();
            }
            envCode = System.getenv("ENV");
            if (envCode != null && !envCode.isEmpty()) {
                return envCode.toLowerCase();
            }

            // 启动参数中获取
            RuntimeMXBean bean = ManagementFactory.getRuntimeMXBean();
            // -Denv=neibu
            List<String> list = bean.getInputArguments();
            for (String item : list) {
                if (item.startsWith("-Denv=")) {
                    envCode = item.substring(6);
                    return envCode.toLowerCase();
                }
            }
        } catch (Exception e) {
            if (logger.isWarnEnabled() && ZeusLoggerConfig.needEnableLogger()) {
                logger.warn("### 宙斯初始化应用运行环境变量信息出现异常 >> errMsg = {}", e.getMessage());
            }
        }
        return ZeusConstant.UNKNOWN;
    }

    /**
     * APP配置
     */
    private static class AppProperties {
        /**
         * 目录
         */
        private static final String PROPERTIES_FILE = "/META-INF/app.properties";

        /**
         * 获取应用ID
         *
         * @return 应用ID
         * @author f1ybear_wang  2022/5/10 15:46
         */
        public static String getAppId() {
            // 初始化应用信息
            InputStream in = null;
            try {
                in = Thread.currentThread().getContextClassLoader().getResourceAsStream(PROPERTIES_FILE);

                if (in == null) {
                    in = ServerInfoUtils.class.getResourceAsStream(PROPERTIES_FILE);
                }
                if (in != null) {
                    Properties prop = new Properties();
                    prop.load(in);

                    String appId = prop.getProperty("app.id");
                    if (appId != null) {
                        return appId;
                    }

                    String appName = prop.getProperty("app.name");
                    if (appName != null) {
                        return appName;
                    }
                }
            } catch (Exception ignored) {

            } finally {
                if (in != null) {
                    try {
                        in.close();
                    } catch (Exception ignored) {
                    }
                }
            }
            return null;
        }
    }
}
